﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Presenter.cs" company="YellowFish">
//   Copyright © YellowFish 2009
// </copyright>
// <summary>
//   Defines the Presenter type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace MobilePal.Views
{
  #region Imported Namespaces


  using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.Linq;
  using System.Windows.Forms;

  using Collections;

  using Log;

  using State;


  #endregion


  internal sealed class Presenter
  {
    #region Constants and Fields


    private readonly Control _control;
    private readonly Collection<ILogger> _loggers = new Collection<ILogger>();
    private readonly ApplicationState _state;
    private readonly ViewProxyCollection _viewProxyCollection = new ViewProxyCollection();

    private IView _currentView;


    #endregion


    #region Constructors and Destructors


    public Presenter(Control control, ApplicationState state)
    {
      _control = control;
      _state = state;

      state.Settings.Views.CollectionChanged += ViewsCollectionChanged;

      // if (!_state.Settings.Views.Any())
      // {
      // CreateDefaultViews();
      // }
      Build();

      _state.Activities.ActivityIsInProgressChanged += ActivityIsInProgressChanged;
    }


    #endregion


    #region Events


    public event EventHandler<ActivityEventArgs> ActivitySelected;
    public event EventHandler<ActivityEventArgs> ActivityToggled;


    /// <summary>
    /// Occurs when current view has changed.
    /// </summary>
    public event EventHandler CurrentViewChanged;


    #endregion


    #region Properties


    /// <exception cref="InvalidOperationException">
    /// CurrentView cannot be <c>null</c>.
    /// </exception>
    public IView CurrentView
    {
      get
      {
        return _currentView;
      }

      set
      {
        if (_currentView != null)
        {
          _currentView.ActivitySelected -= ViewActivitySelected;

          foreach (Control view in CreatedViews)
          {
            view.Visible = false;
          }
        }

        _currentView = value;

        if (CurrentViewChanged != null)
        {
          CurrentViewChanged(this, EventArgs.Empty);
        }

        if (_currentView == null)
        {
          return;
        }

        _currentView.ActivitySelected += ViewActivitySelected;

        var control = (Control)_currentView;
        control.Focus();
        control.Visible = true;
      }
    }


    public Collection<ILogger> Loggers
    {
      get
      {
        return _loggers;
      }
    }


    public IEnumerable<string> ViewsNames
    {
      get
      {
        return _viewProxyCollection.Select(proxy => proxy.ApplicationView.Label);
      }
    }

    private IEnumerable<IView> CreatedViews
    {
      get
      {
        return _viewProxyCollection.Where(proxy => proxy.IsCreated).Select(proxy => proxy.View);
      }
    }


    #endregion


    #region Public Methods


    public IView GetViewLabel(string text)
    {
      ViewProxy viewProxy = _viewProxyCollection.FirstOrDefault(proxy => proxy.ApplicationView.Label == text);

      if (viewProxy != null)
      {
        return viewProxy.View;
      }

      return null;
    }


    #endregion


    #region Methods


    private static ButtonsView.ButtonsView CreateButtonsView(string label)
    {
      return new ButtonsView.ButtonsView {Dock = DockStyle.Fill, Name = label, TabIndex = 0};
    }


    private static TreeView.TreeView CreateTreeView(string label)
    {
      return new TreeView.TreeView {Dock = DockStyle.Fill, Name = label, TabIndex = 0};
    }


    private void ActivityIsInProgressChanged(object sender, ActivityEventArgs activityArgs)
    {
      foreach (ILogger logger in Loggers)
      {
        logger.DumpActivity(activityArgs.Activity);
      }

      if (ActivityToggled != null)
      {
        ActivityToggled(this, new ActivityEventArgs(activityArgs.Activity));
      }
    }


    private void AddView<T>(T view) where T: Control, IView
    {
      _control.Controls.Add(view);

      if (CurrentView == null)
      {
        CurrentView = view;
      }
    }


    private ViewProxy AddView(ApplicationView applicationView)
    {
      var viewProxy = new ViewProxy(applicationView, _state.Activities, _state.Categories, CreateView);

      _viewProxyCollection.Add(viewProxy);

      if (CurrentView == null)
      {
        CurrentView = viewProxy.View;
      }

      if (applicationView.IsDefault)
      {
        CurrentView = viewProxy.View;
      }

      return viewProxy;
    }


    private void Build()
    {
      foreach (ApplicationView applicationView in _state.Settings.Views)
      {
        ViewProxy viewProxy = AddView(applicationView);

        if (CurrentView == null)
        {
          CurrentView = viewProxy.View;
        }
      }
    }


    private void CreateDefaultViews()
    {
      _state.Settings.Views.Add(new ApplicationView
                                  {
                                     ClassName = "ButtonsView", Label = "Buttons View", IsDefault = true
                                  });
      _state.Settings.Views.Add(new ApplicationView {ClassName = "TreeView", Label = "Tree View"});
    }


    private IView CreateView(ApplicationView applicationView)
    {
      switch (applicationView.ClassName)
      {
        case "TreeView":
          TreeView.TreeView treeView = CreateTreeView(applicationView.Label);
          AddView(treeView);

          return treeView;

        case "ButtonsView":
          ButtonsView.ButtonsView buttonsView = CreateButtonsView(applicationView.Label);
          AddView(buttonsView);

          return buttonsView;
      }

      return null;
    }


    private void ProcessAddedViews(IEnumerable<ApplicationView> applicationViews)
    {
      foreach (ApplicationView applicationView in applicationViews)
      {
        AddView(applicationView);
      }
    }


    private void ProcessRemovedViews(IEnumerable<ApplicationView> applicationViews)
    {
      foreach (ApplicationView applicationView in applicationViews)
      {
        RemoveView(applicationView);
      }
    }


    private void RemoveView(ApplicationView applicationView)
    {
      ViewProxy viewProxy = null;

      foreach (ViewProxy proxy in _viewProxyCollection)
      {
        if (proxy.ApplicationView == applicationView)
        {
          viewProxy = proxy;
        }
      }

      if (viewProxy == null)
      {
        return;
      }

      _viewProxyCollection.Remove(viewProxy);

      if (viewProxy.IsCreated)
      {
        _control.Controls.Remove((Control)viewProxy.View);
      }

      if (CurrentView == viewProxy.View)
      {
        CurrentView = null;
      }
    }


    private void ViewActivitySelected(object sender, ActivityEventArgs activityArgs)
    {
      if (ActivitySelected != null)
      {
        ActivitySelected(this, new ActivityEventArgs(activityArgs.Activity));
      }
    }


    private void ViewsCollectionChanged(object sender, NotifyCollectionChangedEventArgs<ApplicationView> e)
    {
      switch (e.Action)
      {
        case NotifyCollectionChangedAction.Add:
          ProcessAddedViews(e.NewItems);
          break;
        case NotifyCollectionChangedAction.Remove:
          ProcessRemovedViews(e.OldItems);
          break;
        case NotifyCollectionChangedAction.Replace:
          ProcessAddedViews(e.NewItems);
          ProcessRemovedViews(e.OldItems);
          break;
      }
    }


    #endregion
  }
}